package com.jfinal.bbsapp.common.config;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.sql.DataSource;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.wall.WallFilter;
import com.jfinal.bbsapp.common.interceptor.CORSInterceptor;
import com.jfinal.bbsapp.common.interceptor.TokenInterceptor;
import com.jfinal.bbsapp.common.model._MappingKit;
import com.jfinal.config.*;
import com.jfinal.core.JFinal;
import com.jfinal.ext.handler.ContextPathHandler;
import com.jfinal.json.MixedJsonFactory;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.dialect.MysqlDialect;
import com.jfinal.plugin.cron4j.Cron4jPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.plugin.ehcache.EhCachePlugin;
import com.jfinal.plugin.redis.RedisPlugin;
import com.jfinal.template.Engine;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration;
import redis.clients.jedis.JedisPoolConfig;

public class CommonConfig extends JFinalConfig {
	private static Prop p;
	private WallFilter wallFilter;
	
	//从左到右依次去找配置，找到则立即加载并立即返回，后续配置将被忽略
	static void loadConfig() {
		if (p == null) { p = PropKit.useFirstFound("config-pro.txt", "config-dev.txt"); }
	}
	
	public void configConstant(Constants me) {
		loadConfig();
		
		me.setDevMode(p.getBoolean("devMode", false));
		me.setJsonFactory(MixedJsonFactory.me());
		
		me.setBaseUploadPath("upload");// 配置文件上传路径
		me.setBaseDownloadPath("/download");//配置文件下载路径
		
		// 支持 Controller、Interceptor、Validator 之中使用 @Inject 注入业务层，并且自动实现 AOP
		me.setInjectDependency(true);
		
		// 是否对超类中的属性进行注入
		me.setInjectSuperClass(true);
		
		me.setError403View("/views/error/403.html");
		//app不用定向错误页
		//me.setError404View("/views/error/404.html");
		me.setError500View("/views/error/500.html");
	}
	
	//分模块管理路由
	public void configRoute(Routes me) {
		me.scan("com.jfinal.bbsapp.");
	}
	
	//配置模板引擎
	public void configEngine(Engine me) {
		me.setDevMode(p.getBoolean("engineDevMode", false));
		// 项目根路径
		me.addSharedObject("path", JFinal.me().getContextPath());
	}
	
	//抽取成独立的方法，便于 _Generator 中重用该方法，减少代码冗余
	public static DruidPlugin getDruidPlugin() {
		loadConfig();
		return new DruidPlugin(p.get("jdbcUrl"), p.get("user"), p.get("password").trim());
	}
	
	public void configPlugin(Plugins me) {
		Map<String, DataSource> dataSourceMap = new HashMap<>();
	    DruidPlugin db0 = getDruidPlugin();
	    wallFilter = new WallFilter();// 加强数据库安全
		wallFilter.setDbType("mysql");
		db0.addFilter(wallFilter);
		db0.addFilter(new StatFilter());// 添加 StatFilter 才会有统计数据
	    db0.start();
	    dataSourceMap.put("db0", db0.getDataSource());
	    
	    //sys_log系统日志表业务表与分表物理表
	    TableRuleConfiguration logRuleConfig = new TableRuleConfiguration("sys_log","db0.sys_log_20250$->{6..9},db0.sys_log_2025$->{10..12}");
	    StandardShardingStrategyConfiguration logShardingStrategyConfig = 
	    		new StandardShardingStrategyConfiguration("logid", new TableShardingAlgorithm());
	    logRuleConfig.setTableShardingStrategyConfig(logShardingStrategyConfig);
	    
	    //c_user_record观看记录表分表物理表
	    TableRuleConfiguration recordRuleConfig = new TableRuleConfiguration("c_user_record","db0.c_user_record_20250$->{6..9},db0.c_user_record_2025$->{10..12}");
	    StandardShardingStrategyConfiguration recordShardingStrategyConfig = 
	    		new StandardShardingStrategyConfiguration("recordid", new TableShardingAlgorithm());
	    recordRuleConfig.setTableShardingStrategyConfig(recordShardingStrategyConfig);
	    
	    //配置规则
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        shardingRuleConfig.getTableRuleConfigs().add(logRuleConfig);
        shardingRuleConfig.getTableRuleConfigs().add(recordRuleConfig);
	    
	    // 获取数据源对象
	    DataSource dataSource = null;
	    try {
	    	Properties properties = new Properties();
	    	properties.setProperty("max.connections.size.per.query", "50");
	        dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig,properties);
	    } catch (SQLException e) {
	        e.printStackTrace();
	    }
	    
	    ActiveRecordPlugin shareArp = new ActiveRecordPlugin(dataSource);
	    shareArp.setTransactionLevel(Connection.TRANSACTION_READ_COMMITTED);
	    //配置数据库方言
	    shareArp.setDialect(new MysqlDialect());
	    shareArp.setDevMode(p.getBoolean("devMode", false));
	    shareArp.setShowSql(p.getBoolean("devMode", false));
	    _MappingKit.mapping(shareArp);
	    me.add(shareArp);
		
		// 配置REDIS缓存插件
		RedisPlugin zRedis = new RedisPlugin(PropKit.get("cacheName"), PropKit.get("HOST"), PropKit.getInt("PORT"),
			PropKit.getInt("MAX_WAIT"), PropKit.get("AUTH"));
		JedisPoolConfig config = zRedis.getJedisPoolConfig();
		config.setMaxIdle(PropKit.getInt("MAX_IDLE"));
		config.setMaxWaitMillis(PropKit.getInt("MAX_WAIT"));
		config.setMaxTotal(PropKit.getInt("MAX_ACTIVE"));
		config.setTestOnBorrow(PropKit.getBoolean("TEST_ON_BORROW"));
		config.setTestWhileIdle(PropKit.getBoolean("TEST_WHILEIDLE"));
		config.setTestOnReturn(PropKit.getBoolean("TEST_ON_RETURN"));
		me.add(zRedis);
		
		// 配置EhCache缓存插件
		me.add(new EhCachePlugin());
		// 配置任务调度
		me.add(new Cron4jPlugin(p));
	}
	
	//配置全局拦截器
	public void configInterceptor(Interceptors me) {
		//跨域
		me.add(new CORSInterceptor());
		// 配置权限访问拦截器先校验token
		me.add(new TokenInterceptor());
	}

	//配置处理器
	public void configHandler(Handlers me) {
		me.add(new ContextPathHandler("ctx"));
	}
}






